/*
 * FeedSyncronizer.java
 *
 * Created on April 11, 2007, 8:13 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.sync;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.atomojo.app.Storage;
import org.atomojo.app.client.XMLRepresentationParser;
import org.atomojo.app.db.DB;
import org.atomojo.app.db.SyncProcess;
import org.atomojo.app.util.Slot;
import org.infoset.xml.XMLException;

/**
 *
 * @author alex
 */
public class FeedSynchronizer implements Runnable
{
   static int defaultSyncPeriod = 1000*60;
   static {
      String value = System.getProperty("org.atomojo.sync.period");
      if (value!=null) {
         defaultSyncPeriod = Integer.parseInt(value);
      }
   }
   DB db;
   Storage storage;
   int pausePeriod;
   boolean running;
   Logger log;
   String username;
   String password;
   XMLRepresentationParser parser = new XMLRepresentationParser();
   
   /** Creates a new instance of FeedSyncronizer */
   public FeedSynchronizer(Logger log,DB db,Storage storage)
   {
      this.db = db;
      this.storage = storage;
      this.pausePeriod = defaultSyncPeriod;
      this.running = true;
      this.log = log;
      this.username = "admin";
      this.password = "admin";
   }
   
   public void stop() {
      this.running = false;
   }
   
   public void run() {
      
      while (running) {
         try {
            Thread.currentThread().sleep(pausePeriod);
         } catch (InterruptedException ex) {
            log.warning("Sleep interrupted on sync.");
         }
         sync();
      }
   }
   
   public void sync() 
   {
      final Slot<Boolean> allOK = new Slot<Boolean>(Boolean.TRUE);
      log.fine("Checking for targets to synchronize...");
      final Date thisSync = new Date();
      try {
         Iterator<SyncProcess> procs = db.getSyncProcesses();
         while (procs.hasNext()) {
            SyncProcess proc = procs.next();
            try {
               proc.unmarshall();
               if (proc.isPullSynchronization()) {
                  continue;
               }
               proc.getSyncTarget().unmarshall();
               proc.getRemoteApp().unmarshall();
               
               log.info("Synchronizing process "+proc.getName()+": target="+proc.getSyncTarget().getName()+", app="+proc.getRemoteApp().getName());
               PushSynchronizer push = new PushSynchronizer(log,db,storage,proc);
               push.setSynchronizationAt(thisSync);
               try {
                  push.sync();
               } catch (TargetNotAvailableException ex) {
                  allOK.set(false);
                  log.warning(ex.getMessage());
               } catch (SyncException ex) {
                  log.log(Level.SEVERE,"Failure to sync process "+proc.getName(),ex);
                  allOK.set(false);
               }
               log.info("Finished sync process "+proc.getName());
            } catch (Exception ex) {
               // No error should happen.. but hey...
               log.log(Level.SEVERE,"Cannot unmarshall document.",ex);
               continue;
            }
         }
         if (allOK.get()) {
            try {
               db.getJournal().truncate(new Timestamp(thisSync.getTime()));
            } catch (SQLException ex) {
               log.log(Level.SEVERE,"Exception while truncating journal: "+ex.getMessage(),ex);
            }
         }
      } catch (XMLException ex) {
         log.log(Level.SEVERE,"Exception when getting push sync process list: "+ex.getMessage(),ex);
      }
      log.fine("Finished synchronization.");
   }
}
